/**
 * 
 */
package com.ydy.remote.wechat;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ydy.exception.BusinessException;
import com.ydy.ienum.EnumSystem;
import com.ydy.model.WechatUser;
import com.ydy.remote.wechat.exception.WeChatException;
import com.ydy.remote.wechat.vo.JsTicket;
import com.ydy.remote.wechat.vo.WeChatTokenVo;
import com.ydy.remote.wechat.vo.WebWeChatTokenVo;
import com.ydy.remote.wechat.vo.custom.BaseMsg;
import com.ydy.remote.wechat.vo.menu.Menu;
import com.ydy.utils.HttpUtil;
import com.ydy.utils.Sha1Util;

/**
 * @author xuzhaojie
 *
 *         2019年6月3日 下午4:44:50
 */
public class WeChatApi {

	private final static Logger log = LoggerFactory.getLogger(WeChatApi.class);

	public static String appId = "wxac2e97087946bf97";
	public static String appSecret = "dbcb9d51af648df33ad745aab30cfc45";
	public static String redirectUri = "http://www.baidu.com";
	private static String TOKEN = "xuzelinxujiacheng";

	private static Object TOKEN_LOCK = new Object();
	private static Object TICKET_LOCK = new Object();
	private static WeChatTokenVo ACCESS_TOKEN = null;
	private static JsTicket JS_TICKET = null;

	private static String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}";

	private static String GET_WEB_CODE = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APPID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

	private static String GET_WEB_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APPID}&secret=${APPSECRET}&code=${code}&grant_type=authorization_code";

	private static String GET_WEB_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=${ACCESS_TOKEN}&openid=${OPENID}&lang=zh_CN";

	private static String GET_JS_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${ACCESS_TOKEN}&type=jsapi";

	private static String CREATE_MENU = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=${ACCESS_TOKEN}";

	private static String CUSTOM_SEND = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${ACCESS_TOKEN}";

	public static final String NOTIFY_SUS = "<xml>" + "  <return_code><![CDATA[SUCCESS]]></return_code>"
			+ "  <return_msg><![CDATA[OK]]></return_msg>" + "</xml>";
	public static final String NOTIFY_FAIL = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
			+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";

	public static WeChatTokenVo requestAccessToken() {
		String url = GET_ACCESS_TOKEN_URL.replace("${APPID}", appId).replace("${APPSECRET}", appSecret);
		String result = HttpUtil.doGet(url);
		if (result == null || "".equals(result)) {
			log.error("微信远程网络出现错误:" + GET_ACCESS_TOKEN_URL);
			throw new WeChatException("微信远程网络出现错误");
		}
		JSONObject json = JSONObject.parseObject(result);
		if (json.containsKey("errcode")) {
			Long errcode = json.getLong("errcode");
			String msg = json.getString("errmsg");
			log.error("微信请求错误,返回结果:" + result);
			throw new WeChatException(errcode, msg);
		}
		log.info("微信请求成功,返回结果:" + json);
		WeChatTokenVo tokenVo = new WeChatTokenVo();
		tokenVo.setAccessToken(json.getString("access_token"));
		tokenVo.setExpiresIn(json.getLong("expires_in"));
		return tokenVo;
	}

	public static WeChatTokenVo getAccessToken() {
		if (ACCESS_TOKEN == null || ACCESS_TOKEN.isExpire()) {
			synchronized (TOKEN_LOCK) {
				if (ACCESS_TOKEN == null || ACCESS_TOKEN.isExpire()) {
					ACCESS_TOKEN = requestAccessToken();
				}
			}
		}
		return ACCESS_TOKEN;
	}

	public static void setAccessToken(WeChatTokenVo tokenVo) {
		ACCESS_TOKEN = tokenVo;
	}

	public static JsTicket getJsTicket() {
		if (JS_TICKET == null || JS_TICKET.isExpire()) {
			synchronized (TICKET_LOCK) {
				if (JS_TICKET == null || JS_TICKET.isExpire()) {
					String url = GET_JS_TICKET.replace("${ACCESS_TOKEN}", getAccessToken().getAccessToken());
					String result = HttpUtil.doGet(url);
					if (result == null || "".equals(result)) {
						log.error("微信远程网络出现错误:" + GET_JS_TICKET);
						throw new WeChatException("微信远程网络出现错误");
					}
					JSONObject json = JSONObject.parseObject(result);
					if (json.containsKey("errcode") && !json.getInteger("errcode").equals(0)) {
						Long errcode = json.getLong("errcode");
						String msg = json.getString("errmsg");
						log.error("微信请求错误,返回结果:" + result);
						throw new WeChatException(errcode, msg);
					}
					log.error("微信请求成功,返回结果:" + json);
					JS_TICKET = new JsTicket();
					JS_TICKET.setTicket(json.getString("ticket"));
					JS_TICKET.setExpiresIn(json.getLong("expires_in"));
				}
			}
		}
		return JS_TICKET;
	}

	public static String getLoginUrl(String reUrl) {
		if (reUrl == null || "".equals(reUrl)) {
			reUrl = redirectUri;
		}
		try {
			reUrl = URLEncoder.encode(reUrl, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			log.error("系统内部编码出现错误");
			throw new BusinessException(EnumSystem.ENCODE_ERROR);
		}
		String url = GET_WEB_CODE.replace("${APPID}", appId).replace("${REDIRECT_URI}", reUrl);
		return url;
	}

	public static WebWeChatTokenVo getWebAccessToken(String code) {
		if (code == null || "".equals(code)) {
			log.error("微信登录code是必填参数");
			throw new WeChatException("微信登录code是必填参数");
		}
		String url = GET_WEB_ACCESS_TOKEN_URL.replace("${APPID}", appId).replace("${APPSECRET}", appSecret)
				.replace("${code}", code);
		String result = HttpUtil.doGet(url);
		if (result == null || "".equals(result)) {
			log.error("微信远程网络出现错误:" + GET_WEB_ACCESS_TOKEN_URL);
			throw new WeChatException("微信远程网络出现错误");
		}
		JSONObject json = JSONObject.parseObject(result);
		if (json.containsKey("errcode")) {
			Long errcode = json.getLong("errcode");
			String msg = json.getString("errmsg");
			log.error("微信请求错误,返回结果:" + result);
			throw new WeChatException(errcode, msg);
		}
		WebWeChatTokenVo vo = new WebWeChatTokenVo();
		vo.setAccessToken(json.getString("access_token"));
		vo.setExpiresIn(json.getLong("expires_in"));
		vo.setRefreshToken(json.getString("refresh_token"));
		vo.setOpenid(json.getString("openid"));
		vo.setScope(json.getString("scope"));
		return vo;
	}

	public static WechatUser getUserInfo(WebWeChatTokenVo webWeChatTokenVo) {
		if (webWeChatTokenVo == null || webWeChatTokenVo.getAccessToken() == null
				|| webWeChatTokenVo.getOpenid() == null) {
			log.error("微信用户信息获取请求参数缺失");
			throw new WeChatException("微信用户信息获取请求参数缺失");
		}
		String url = GET_WEB_USER_INFO.replace("${ACCESS_TOKEN}", webWeChatTokenVo.getAccessToken())
				.replace("${OPENID}", webWeChatTokenVo.getOpenid());
		String result = HttpUtil.doGet(url);
		if (result == null || "".equals(result)) {
			log.error("微信远程网络出现错误:" + GET_WEB_USER_INFO);
			throw new WeChatException("微信远程网络出现错误");
		}
		log.info("微信返回:" + result);
		JSONObject json = JSONObject.parseObject(result);
		if (json.containsKey("errcode")) {
			Long errcode = json.getLong("errcode");
			String msg = json.getString("errmsg");
			log.error("微信请求错误,返回结果:" + result);
			throw new WeChatException(errcode, msg);
		}
		WechatUser info = JSONObject.parseObject(result, WechatUser.class);
		return info;
	}

	public static JSONObject createMenu(Menu menu) {
		if (menu == null) {
			log.error("微信菜单获取请求参数缺失");
			throw new WeChatException("微信菜单获取请求参数缺失");
		}
		String url = CREATE_MENU.replace("${ACCESS_TOKEN}", getAccessToken().getAccessToken());
		String result = HttpUtil.doPost(url, JSON.toJSONString(menu));
		if (result == null || "".equals(result)) {
			log.error("微信远程网络出现错误:" + CREATE_MENU);
			throw new WeChatException("微信远程网络出现错误");
		}
		log.info("微信返回:" + result);
		JSONObject json = JSONObject.parseObject(result);
		if (json.containsKey("errcode")) {
			Long errcode = json.getLong("errcode");
			String msg = json.getString("errmsg");
			log.error("微信请求错误,返回结果:" + result);
			throw new WeChatException(errcode, msg);
		}
		return json;
	}

	public static JSONObject customSend(BaseMsg msg) {
		if (msg == null) {
			log.error("微信客服发送获取请求参数缺失");
			throw new WeChatException("微信客服发送获取请求参数缺失");
		}
		String url = CUSTOM_SEND.replace("${ACCESS_TOKEN}", getAccessToken().getAccessToken());
		String result = HttpUtil.doPost(url, JSON.toJSONString(msg));
		if (result == null || "".equals(result)) {
			log.error("微信远程网络出现错误:" + CREATE_MENU);
			throw new WeChatException("微信远程网络出现错误");
		}
		log.info("微信返回:" + result);
		JSONObject json = JSONObject.parseObject(result);
		return json;
	}

	public static String makeSign(String timestamp, String nonce) {
		String token = TOKEN;
		String[] array = new String[] { token, timestamp, nonce };
		StringBuffer sb = new StringBuffer();
		// 字符串排序
		Arrays.sort(array);
		for (int i = 0; i < 3; i++) {
			sb.append(array[i]);
		}
		String str = sb.toString();
		// SHA1签名生成
		return Sha1Util.getSha1(str);
	}

	public static void main(String[] args) {
		// System.out.println(JSON.toJSON(getLoginUrl()));
		System.out.println(JSON.toJSON(getAccessToken()));
		// System.out.println(JSON.toJSON(getUserInfo(getWebAccessToken("011xi9tS0Ljmb624v7tS0ZpetS0xi9tl"))));
	}
}
